﻿using Org.BouncyCastle.Crypto;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Mmeller.Net.Decoder
{
    class Cryptor<Engine> where Engine : IBlockCipher
    {
        private CryptoEngine<Engine> engine;
        private XmlHeader fileHeader;

        public Cryptor()
        {
            this.engine = new CryptoEngine<Engine>();
            this.fileHeader = new XmlHeader("crypto");
        }

        public Cryptor(CryptoMode mode, int blockLength)
        {
            this.engine = new CryptoEngine<Engine>(mode, blockLength);
            this.fileHeader = new XmlHeader("crypto");
        }

        public void encryptFile(string input, string output, int keyLength)
        {
            FileStream inputStream;
            FileStream outputStream;
            prepareStreams(input, output, out inputStream, out outputStream);

            this.encryptFile(inputStream, outputStream, keyLength);
        }

        private static void prepareStreams(string input, string output, out FileStream inputStream, out FileStream outputStream)
        {
            inputStream = new FileStream(input, FileMode.Open);
            outputStream = new FileStream(output, FileMode.Append);
        }

        public void decryptFile(string input, string output, int keyLength)
        {
            FileStream inputStream;
            FileStream outputStream;
            prepareStreams(input, output, out inputStream, out outputStream);

            this.decryptFile(inputStream, outputStream, keyLength);
        }

        public void decryptFile(FileStream inputStream, FileStream outputStream, int keyLength)
        {
            BinaryReader reader;
            BinaryWriter writer;
            prepareReaders(inputStream, outputStream, out reader, out writer);

            //this.engine.decryptorInit(

            reader.Close();
            writer.Close();
        }



        public void encryptFile(FileStream inputStream, FileStream outputStream, int keyLength)
        {
            this.engine.cryptorInit(keyLength);

            BinaryReader reader;
            BinaryWriter writer;
            prepareReaders(inputStream, outputStream, out reader, out writer);

            writer.Seek(0, SeekOrigin.End);

            try
            {
                long position = 0;
                long length = reader.BaseStream.Length;

                int blockSize = 16 * 12;

                while (position < length)
                {
                    writer.Write(encryptData(reader, blockSize));
                    position += blockSize;
                }
                doFinal(writer, blockSize);
            }
            catch (InvalidCipherTextException e)
            {
                processException(e);
            }

            reader.Close();
            writer.Close();
        }

        private static void prepareReaders(FileStream inputStream, FileStream outputStream, out BinaryReader reader, out BinaryWriter writer)
        {
            reader = new BinaryReader(inputStream);
            writer = new BinaryWriter(outputStream);
        }

        private void doFinal(BinaryWriter writer, int blockSize)
        {
            byte[] outputData = this.engine.encryptFinalData(blockSize);
            if (outputData != null)
            {
                writer.Write(outputData);
            }
        }

        private void processException(InvalidCipherTextException e)
        {
            throw new NotImplementedException();
        }


        private byte[] encryptData(BinaryReader reader, int blockSize)
        {
            byte[] inputText = reader.ReadBytes(blockSize);
            return this.engine.encryptData(inputText);
        }

    }
}

/*
public void odszyfrujPlik(string decryptInput, string decryptOutput, string sciezkaDoKlucza, string hasloDoKlucza,
            ToolStripProgressBar pasekPostepu)
        {

            string tempSzyfrogram = @"C:\tempSzyfrogram";
            string tempNaglowek = @"C:\tempNaglowek.xml";

            HeaderCreator creator = new HeaderCreator();

            string nazwaAlgorytmu, trybPracy;
            int dlugoscKlucza, dlugoscPodbloku;
            byte[] kluczSesyjny, wektorPoczatkowy;

            string[] temp = sciezkaDoKlucza.Split('\\');
            string nazwisko = temp[temp.Count() - 2];

            creator.odczytajNaglowek(decryptInput, nazwisko, tempNaglowek, tempSzyfrogram, out nazwaAlgorytmu, out dlugoscKlucza, out kluczSesyjny, out dlugoscPodbloku, out wektorPoczatkowy, out trybPracy, hasloDoKlucza);

            if ((nazwaAlgorytmu == "RC 6") && (kluczSesyjny != null))
            {
                FileStream wejscie = new FileStream(tempSzyfrogram, FileMode.Open);
                FileStream wyjscie = new FileStream(decryptOutput, FileMode.CreateNew);

                BinaryReader reader = new BinaryReader(wejscie);
                BinaryWriter writer = new BinaryWriter(wyjscie);

                if (trybPracy == "ECB")
                {
                    this.dekryptorPliku.Init(false, new KeyParameter(kluczSesyjny));
                }
                else
                {
                    this.ustawTryb(trybPracy, dlugoscPodbloku);
                    KeyParameter parametr = new KeyParameter(kluczSesyjny);
                    ParametersWithIV iv = new ParametersWithIV(parametr, wektorPoczatkowy);
                    this.dekryptorPliku.Init(false, iv);
                }

                przetwarzaj(reader, writer, this.dekryptorPliku, pasekPostepu);

                reader.Close();
                writer.Close();

            }

            File.Delete(tempSzyfrogram);
            File.Delete(tempNaglowek);
        }

*/